//
//  AlbumLogic.m
//  SecretAlbums
//
//  Created by BabyFinancial on 15/6/16.
//  Copyright (c) 2015年 BabyFinancial. All rights reserved.
//

#import "SecretAlbumsLogic.h"
#import "Album.h"
#import "Media.h"
#import "MagicalRecord.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import "ALAsset+assetType.h"
#import "NSDateFormatter+timeIntervalFormatter.h"
#import "SecretAlbumsPersistence.h"
#import "UIImage+SecretAlbums.h"
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

@interface SecretAlbumsLogic ()

// 当前登录相册ID，登录成功时进行赋值，删除或者注销相册时清空
@property (nonatomic, strong) NSString *currentAlbumID;

@end

@implementation SecretAlbumsLogic

static SecretAlbumsLogic *sharedManager = nil;
+ (instancetype)sharedManager
{
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedManager = [SecretAlbumsLogic new];
        sharedManager.currentAlbumID = [NSString new];
    });
    
    return sharedManager;
}

/** 创建相册 */
+ (void)createAlbumWithID:(NSString *)albumID
{
    NSArray *albumArray = [Album MR_findByAttribute:@"albumID" withValue:albumID];
    
    if (0 == albumArray.count) {
        Album *album = [Album MR_createEntity];
        album.albumID = albumID;
        [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
        [[SecretAlbumsPersistence sharedManager] createDirectoryAtAlbumID:albumID];
    }
}

/** 删除相册并清空当前登录相册ID（必须为登录状态） */
+ (void)removeAlbum
{
    ;
}

/** 登录相册并设置当前登录相册ID */
+ (BOOL)loginWithID:(NSString *)albumID
{
    sharedManager = [SecretAlbumsLogic sharedManager];
    NSArray *albumArray = [Album MR_findByAttribute:@"albumID" withValue:albumID];
    
    if (0 != albumArray.count) {
        sharedManager.currentAlbumID = albumID;
        return YES;
    } else {
        return NO;
    }
}

/** 注销相册并清空当前登录相册ID（必须为登录状态） */
+ (void)logout
{
    sharedManager = [SecretAlbumsLogic sharedManager];
    sharedManager.currentAlbumID = @"";
}

/** 获取当前相册ID */
+ (NSString *)currentAlbumID
{
    sharedManager = [SecretAlbumsLogic sharedManager];
    return sharedManager.currentAlbumID;
}

/** 获取当前相册ID中的媒体信息（必须为登录状态） */
+ (NSArray *)mediaArrayWithCurrentAlbumID
{
    sharedManager = [SecretAlbumsLogic sharedManager];
    Album *album = [Album MR_findByAttribute:@"albumID" withValue:sharedManager.currentAlbumID].firstObject;
    NSArray *sortDesc = @[[[NSSortDescriptor alloc] initWithKey:@"createTime" ascending:YES]];
    NSArray *thumbnailArray = [album.media sortedArrayUsingDescriptors:sortDesc];
    
    return thumbnailArray;
}

/** 添加照片至当前相册（必须为登录状态） */
+ (void)addAssets:(NSArray *)assets completion:(void (^)(void))completion
{
    if (assets.count <= 0) {
        completion();
        return;
    }
    
    sharedManager = [SecretAlbumsLogic sharedManager];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue setMaxConcurrentOperationCount:1];
    
    for (int i=0; i<assets.count; i++) {
        NSDate *date = [NSDate date];
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat: @"yyyy-MM-dd-HH-mm-ss-SSS"];
        NSString *dateString = [dateFormatter stringFromDate:date];
        
        ALAsset *asset = assets[i];
        NSString *name = [NSString stringWithFormat:@"%@+%@", dateString, asset.defaultRepresentation.filename];
        NSDictionary *dic = @{@"Asset":asset, @"Date":date, @"Name":name};
        
        // 拷贝缩略图-方形 并 保存CoreData
        NSInvocationOperation *operationThumbnail = [[NSInvocationOperation alloc] initWithTarget:sharedManager selector:@selector(copyThumbnailInApplicationDocumentsDirectoryAndSaveCoreData:) object:dic];
        [queue addOperation:operationThumbnail];
        
        // 拷贝缩略图-原型
        NSInvocationOperation *operationAspectRatioThumbnail = [[NSInvocationOperation alloc] initWithTarget:sharedManager selector:@selector(copyAspectRatioThumbnailInApplicationDocumentsDirectory:) object:dic];
        [queue addOperation:operationAspectRatioThumbnail];
        
        // 拷贝媒体信息-分段处理（1M）
        NSInvocationOperation *lastOperation = [sharedManager lastOperationAndCreateCopyMediaOperations:dic operationQueue:queue];
        
        if (i == assets.count - 1) {
            [lastOperation setCompletionBlock:^{
                dispatch_async(dispatch_get_main_queue(), ^{
                    completion();
                });
            }];
        }
    }
}

/** 添加媒体至当前相册（为应用内部拍摄，必须为登录状态） */
+ (void)addMedia:(NSDictionary *)info completion:(void (^)(void))completion
{
    if (!info) {
        completion();
        return;
    }
    
    NSDate *date = [NSDate date];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat: @"yyyy-MM-dd-HH-mm-ss-SSS"];
    NSString *dateString = [dateFormatter stringFromDate:date];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue setMaxConcurrentOperationCount:1];
    
    UIImage *image;
    NSString *name;
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:@"public.movie"]) {
        NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
        MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:url];
        [player setShouldAutoplay:NO];
        image = [player thumbnailImageAtTime:0.0f timeOption:MPMovieTimeOptionNearestKeyFrame];
        name = [NSString stringWithFormat:@"%@.MOV", dateString];
    } else {
        image = [info objectForKey:UIImagePickerControllerOriginalImage];
        name = [NSString stringWithFormat:@"%@.JPG", dateString];
    }
    
    NSDictionary *dic = @{@"Info":info, @"Date":date, @"Name":name};
    sharedManager = [SecretAlbumsLogic sharedManager];
    [sharedManager createEntityWithInfo:dic];
    
    NSBlockOperation *operationThumbnail = [NSBlockOperation blockOperationWithBlock:^{
        [[SecretAlbumsPersistence sharedManager]
         createThumbnailAtAlbumID:sharedManager.currentAlbumID
         name:name
         data:UIImagePNGRepresentation([image thumbnail])];
    }];
    [queue addOperation:operationThumbnail];
    
    NSBlockOperation *operationAspectRatioThumbnail = [NSBlockOperation blockOperationWithBlock:^{
        [[SecretAlbumsPersistence sharedManager]
         createAspectRatioThumbnailAtAlbumID:sharedManager.currentAlbumID
         name:name
         data:UIImageJPEGRepresentation([image aspectRatioThumbnail], 1.0f)];
    }];
    [queue addOperation:operationAspectRatioThumbnail];
    
    if ([mediaType isEqualToString:@"public.movie"]) {
        // 拷贝媒体信息-分段处理（1M）
        NSInvocationOperation *lastOperation = [sharedManager lastOperationAndCreateCopyMediaOperationsByInfo:dic operationQueue:queue];
        
        [lastOperation setCompletionBlock:^{
            dispatch_async(dispatch_get_main_queue(), ^{
                completion();
            });
        }];
    } else {
        NSBlockOperation *operationOriginalImage = [NSBlockOperation blockOperationWithBlock:^{
            [[SecretAlbumsPersistence sharedManager]
             createMediaAtAlbumID:self.currentAlbumID
             name:name
             data:UIImageJPEGRepresentation(image, 0.7f)];
        }];
        [queue addOperation:operationOriginalImage];
        
        [operationOriginalImage setCompletionBlock:^{
            dispatch_async(dispatch_get_main_queue(), ^{
                completion();
            });
        }];
    }
}

/** 添加应用内部媒体至系统相册（必须为登录状态） */
+ (void)addMediaToSystemAlbum:(NSArray *)medias completion:(void (^)(void))completion
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue setMaxConcurrentOperationCount:1];
    
    for (int i=0; i<medias.count; i++) {
        Media *media = medias[i];
        NSBlockOperation *blockOperation;
        
        if (media.isVideo.boolValue) {
            blockOperation = [NSBlockOperation blockOperationWithBlock:^{
                UISaveVideoAtPathToSavedPhotosAlbum([SecretAlbumsLogic pathWithMediaType:MediaTypeMedia name:media.fileName], nil, nil, nil);
            }];
        } else {
            blockOperation = [NSBlockOperation blockOperationWithBlock:^{
                UIImageWriteToSavedPhotosAlbum([UIImage imageWithContentsOfFile:[SecretAlbumsLogic pathWithMediaType:MediaTypeMedia name:media.fileName]], nil, nil, nil);
            }];
        }
        
        if (i == medias.count-1) {
            [blockOperation setCompletionBlock:^{
                dispatch_async(dispatch_get_main_queue(), ^{
                    completion();
                });
            }];
        }
        
        [queue addOperation:blockOperation];
    }
}

/** 删除照片从当前相册（必须为登录状态） */
+ (void)delMedias:(NSArray *)medias
{
    for (Media *media in medias) {
        //  删除本地文件
        [[SecretAlbumsPersistence sharedManager] removeThumbnailAtAlbumID:sharedManager.currentAlbumID name:media.fileName];
        [[SecretAlbumsPersistence sharedManager] removeAspectRatioThumbnailAtAlbumID:sharedManager.currentAlbumID name:media.fileName];
        [[SecretAlbumsPersistence sharedManager] removeMediaAtAlbumID:sharedManager.currentAlbumID name:media.fileName];
        
        // 删除数据库信息
        [media MR_deleteEntity];
        [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
    }
}

/** 返回MediaType对应文件路径 */
+ (NSString *)pathWithMediaType:(MediaType)mediaType name:(NSString *)name
{
    NSString *resultPath = @"";
    
    if (mediaType == MediaTypeThumbnail) {
        resultPath = [[SecretAlbumsPersistence sharedManager] thumbnailDirectoryAtAlbumID:sharedManager.currentAlbumID];
    } else if (mediaType == MediaTypeAspectRatioThumbnail) {
        resultPath = [[SecretAlbumsPersistence sharedManager] aspectRatioThumbnailDirectoryAtAlbumID:sharedManager.currentAlbumID];
    } else  if (mediaType == MediaTypeMedia) {
        resultPath = [[SecretAlbumsPersistence sharedManager] mediaDirectoryAtAlbumID:sharedManager.currentAlbumID];
    }
    
    resultPath = resultPath.length == 0 ? @"" : [resultPath stringByAppendingPathComponent:name];
    
    return resultPath;
}

#pragma mark - 私有方法

/** 创建实体并保存coredata */
- (void)createEntityWithAsset:(NSDictionary *)dic
{
    ALAsset *asset = [dic objectForKey:@"Asset"];
    NSDate *date = [dic objectForKey:@"Date"];
    NSString *name = [dic objectForKey:@"Name"];
    
    Album *album = [Album MR_findByAttribute:@"albumID" withValue:self.currentAlbumID].firstObject;
    Media *media = [Media MR_createEntity];
    
    // 创建时间
    media.createTime = date;
    
    // 是否是视频
    media.isVideo = [NSNumber numberWithBool:[asset isVideo]];
    
    // 视频时间
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    media.propertyDuration = [df stringFromTimeInterval:[[asset valueForProperty:ALAssetPropertyDuration] doubleValue]];
    
    // 宽度
    media.width = @(asset.defaultRepresentation.dimensions.width);
    
    // 高度
    media.height = @(asset.defaultRepresentation.dimensions.height);
    
    // 文件名
    media.fileName = name;
    
    // 表数据关联
    media.album = album;
    [album addMediaObject:media];
    
    // 存储数据
    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
}

/** 创建实体并保存coredata */
- (void)createEntityWithInfo:(NSDictionary *)dic
{
    NSDictionary *info = [dic objectForKey:@"Info"];
    NSDate *date = [dic objectForKey:@"Date"];
    NSString *name = [dic objectForKey:@"Name"];
    
    Album *album = [Album MR_findByAttribute:@"albumID" withValue:self.currentAlbumID].firstObject;
    Media *media = [Media MR_createEntity];
    
    // 创建时间
    media.createTime = date;
    
    // 是否是视频
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    media.isVideo = @([mediaType isEqualToString:@"public.movie"]);
    
    // 视频时间
    if ([mediaType isEqualToString:@"public.movie"]) {
        AVURLAsset* asset =[AVURLAsset URLAssetWithURL:[info objectForKey:UIImagePickerControllerMediaURL] options:nil];
        CMTime duration = asset.duration;
        float durationSeconds =CMTimeGetSeconds(duration);
        
        NSDateFormatter *df = [[NSDateFormatter alloc] init];
        media.propertyDuration = [df stringFromTimeInterval:durationSeconds];
    }
    
    // 宽度
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    media.width = @(image.size.width);
    
    // 高度
    media.height = @(image.size.height);
    
    // 文件名
    media.fileName = name;
    
    // 表数据关联
    media.album = album;
    [album addMediaObject:media];
    
    // 存储数据
    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
}

/** 拷贝缩略图-方形到系统目录 并 保存CoreData */
- (void)copyThumbnailInApplicationDocumentsDirectoryAndSaveCoreData:(NSDictionary *)dic
{
    // 保存CoreData
    dispatch_async(dispatch_get_main_queue(), ^{
        [sharedManager createEntityWithAsset:dic];
    });
    
    ALAsset *asset = [dic objectForKey:@"Asset"];
    NSString *name = [dic objectForKey:@"Name"];

    // 缩略图——方形
    [[SecretAlbumsPersistence sharedManager]
     createThumbnailAtAlbumID:self.currentAlbumID
     name:name
     data:UIImagePNGRepresentation([UIImage imageWithCGImage:asset.thumbnail])];
}

/** 拷贝缩略图-原型到系统目录 */
- (void)copyAspectRatioThumbnailInApplicationDocumentsDirectory:(NSDictionary *)dic
{
    ALAsset *asset = [dic objectForKey:@"Asset"];
    NSString *name = [dic objectForKey:@"Name"];
    
    // 缩略图——原形
    [[SecretAlbumsPersistence sharedManager]
     createAspectRatioThumbnailAtAlbumID:self.currentAlbumID
     name:name
     data:UIImageJPEGRepresentation([UIImage imageWithCGImage:asset.aspectRatioThumbnail], 1.0f)];
}

/** 创建分段拷贝媒体信息队列，返回最后一个节点 */
- (NSInvocationOperation *)lastOperationAndCreateCopyMediaOperations:(NSDictionary *)dic operationQueue:(NSOperationQueue *)queue
{
    ALAsset *asset = [dic objectForKey:@"Asset"];
    NSString *name = [dic objectForKey:@"Name"];
    
    NSUInteger copySize = 1024 * 1024;     // 每次拷贝的数据Size
    NSUInteger copyNum = (NSUInteger)(asset.defaultRepresentation.size / copySize);
    NSUInteger remaindByte = asset.defaultRepresentation.size % copySize;
    
    NSInvocationOperation *lastOperation;
    for (NSUInteger i = 0; i<copyNum; i++) {
        NSUInteger offset = i*copySize;
        NSDictionary *copyDic = @{@"Asset":asset, @"Name":name, @"CopySize":@(copySize), @"Offset":@(offset)};
        
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:sharedManager selector:@selector(copyMediaInApplicationDocumentsDirectoryWithData:) object:copyDic];
        if (i == copyNum-1) {
            lastOperation = operation;
        }
        
        [queue addOperation:operation];
    }
    
    if (0 != remaindByte) {
        NSUInteger offset = copyNum * copySize;
        NSDictionary *copyDic = @{@"Asset":asset, @"Name":name, @"CopySize":@(remaindByte), @"Offset":@(offset)};
        
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:sharedManager selector:@selector(copyMediaInApplicationDocumentsDirectoryWithData:) object:copyDic];
        lastOperation = operation;
        
        [queue addOperation:operation];
    }
    
    return lastOperation;
}

/** 分段拷贝媒体信息到目录 */
- (void)copyMediaInApplicationDocumentsDirectoryWithData:(NSDictionary *)dic
{
    ALAsset *asset = [dic objectForKey:@"Asset"];
    NSString *name = [dic objectForKey:@"Name"];
    NSNumber *copySize = [dic objectForKey:@"CopySize"];
    NSNumber *offset = [dic objectForKey:@"Offset"];
    
    Byte *buffer = (Byte*)malloc(copySize.integerValue);
    NSUInteger buffered = [asset.defaultRepresentation getBytes:buffer fromOffset:offset.integerValue length:copySize.integerValue error:nil];
    NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
    
    // 分段拷贝
    [[SecretAlbumsPersistence sharedManager]
     createMediaAtAlbumID:self.currentAlbumID
     name:name
     data:data];
}

/** 创建分段拷贝媒体信息队列，返回最后一个节点 */
- (NSInvocationOperation *)lastOperationAndCreateCopyMediaOperationsByInfo:(NSDictionary *)dic operationQueue:(NSOperationQueue *)queue
{
    NSDictionary *info = [dic objectForKey:@"Info"];
    NSData *data = [NSData dataWithContentsOfURL:[info objectForKey:UIImagePickerControllerMediaURL] options:NSDataReadingMappedIfSafe error:nil];
    
    NSString *name = [dic objectForKey:@"Name"];
    
    NSUInteger copySize = 1024 * 1024;     // 每次拷贝的数据Size
    NSUInteger copyNum = (NSUInteger)(data.length / copySize);
    NSUInteger remaindByte = data.length % copySize;
    
    NSInvocationOperation *lastOperation;
    for (NSUInteger i = 0; i<copyNum; i++) {
        NSUInteger offset = i*copySize;
        NSDictionary *copyDic = @{@"Data":data, @"Name":name, @"CopySize":@(copySize), @"Offset":@(offset)};
        
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:sharedManager selector:@selector(copyMediaInApplicationDocumentsDirectoryWithDataByInfo:) object:copyDic];
        if (i == copyNum-1) {
            lastOperation = operation;
        }
        
        [queue addOperation:operation];
    }
    
    if (0 != remaindByte) {
        NSUInteger offset = copyNum * copySize;
        NSDictionary *copyDic = @{@"Data":data, @"Name":name, @"CopySize":@(remaindByte), @"Offset":@(offset)};
        
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:sharedManager selector:@selector(copyMediaInApplicationDocumentsDirectoryWithDataByInfo:) object:copyDic];
        lastOperation = operation;
        
        [queue addOperation:operation];
    }
    
    return lastOperation;
}

/** 分段拷贝媒体信息到目录 */
- (void)copyMediaInApplicationDocumentsDirectoryWithDataByInfo:(NSDictionary *)dic
{
    NSData *data = [dic objectForKey:@"Data"];
    
    NSString *name = [dic objectForKey:@"Name"];
    NSNumber *copySize = [dic objectForKey:@"CopySize"];
    NSNumber *offset = [dic objectForKey:@"Offset"];
    
    Byte *buffer = (Byte*)malloc(copySize.integerValue);
    [data getBytes:buffer range:NSMakeRange(offset.integerValue, copySize.integerValue)];
    
    // 分段拷贝
    [[SecretAlbumsPersistence sharedManager]
     createMediaAtAlbumID:self.currentAlbumID
     name:name
     data:[NSData dataWithBytesNoCopy:buffer length:copySize.integerValue freeWhenDone:YES]];
}

@end
